home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / ifx.php < prev    next >
PHP Script  |  2004-10-01  |  18KB  |  580 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Tomas V.V.Cox <cox@idecnet.com>                              |
  17. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: ifx.php,v 1.47 2004/03/05 01:46:53 danielc Exp $
  21.  
  22.  
  23. // Legend:
  24. // For more info on Informix errors see:
  25. // http://www.informix.com/answers/english/ierrors.htm
  26. //
  27. // TODO:
  28. //  - set needed env Informix vars on connect
  29. //  - implement native prepare/execute
  30.  
  31.  
  32. require_once 'DB/common.php';
  33.  
  34. /**
  35.  * Database independent query interface definition for PHP's Informix
  36.  * extension.
  37.  *
  38.  * @package  DB
  39.  * @version  $Id: ifx.php,v 1.47 2004/03/05 01:46:53 danielc Exp $
  40.  * @category Database
  41.  * @author   Tomas V.V.Cox <cox@idecnet.com>
  42.  */
  43. class DB_ifx extends DB_common
  44. {
  45.     // {{{ properties
  46.  
  47.     var $connection;
  48.     var $affected = 0;
  49.     var $dsn = array();
  50.     var $transaction_opcount = 0;
  51.     var $autocommit = true;
  52.     var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */
  53.  
  54.     // }}}
  55.     // {{{ constructor
  56.  
  57.     function DB_ifx()
  58.     {
  59.         $this->phptype = 'ifx';
  60.         $this->dbsyntax = 'ifx';
  61.         $this->features = array(
  62.             'prepare' => false,
  63.             'pconnect' => true,
  64.             'transactions' => true,
  65.             'limit' => 'emulate'
  66.         );
  67.         $this->errorcode_map = array(
  68.             '-201'    => DB_ERROR_SYNTAX,
  69.             '-206'    => DB_ERROR_NOSUCHTABLE,
  70.             '-217'    => DB_ERROR_NOSUCHFIELD,
  71.             '-239'    => DB_ERROR_CONSTRAINT,
  72.             '-253'    => DB_ERROR_SYNTAX,
  73.             '-292'    => DB_ERROR_CONSTRAINT_NOT_NULL,
  74.             '-310'    => DB_ERROR_ALREADY_EXISTS,
  75.             '-329'    => DB_ERROR_NODBSELECTED,
  76.             '-346'    => DB_ERROR_CONSTRAINT,
  77.             '-386'    => DB_ERROR_CONSTRAINT_NOT_NULL,
  78.             '-391'    => DB_ERROR_CONSTRAINT_NOT_NULL,
  79.             '-554'    => DB_ERROR_SYNTAX,
  80.             '-691'    => DB_ERROR_CONSTRAINT,
  81.             '-703'    => DB_ERROR_CONSTRAINT_NOT_NULL,
  82.             '-1204'   => DB_ERROR_INVALID_DATE,
  83.             '-1205'   => DB_ERROR_INVALID_DATE,
  84.             '-1206'   => DB_ERROR_INVALID_DATE,
  85.             '-1209'   => DB_ERROR_INVALID_DATE,
  86.             '-1210'   => DB_ERROR_INVALID_DATE,
  87.             '-1212'   => DB_ERROR_INVALID_DATE,
  88.             '-1213'   => DB_ERROR_INVALID_NUMBER,
  89.         );
  90.     }
  91.  
  92.     // }}}
  93.     // {{{ connect()
  94.  
  95.     /**
  96.      * Connect to a database and log in as the specified user.
  97.      *
  98.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  99.      * @param $persistent (optional) whether the connection should
  100.      *        be persistent
  101.      *
  102.      * @return int DB_OK on success, a DB error code on failure
  103.      */
  104.     function connect($dsninfo, $persistent = false)
  105.     {
  106.         if (!DB::assertExtension('informix') &&
  107.             !DB::assertExtension('Informix'))
  108.         {
  109.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  110.         }
  111.         $this->dsn = $dsninfo;
  112.         $dbhost = $dsninfo['hostspec'] ? '@' . $dsninfo['hostspec'] : '';
  113.         $dbname = $dsninfo['database'] ? $dsninfo['database'] . $dbhost : '';
  114.         $user = $dsninfo['username'] ? $dsninfo['username'] : '';
  115.         $pw = $dsninfo['password'] ? $dsninfo['password'] : '';
  116.  
  117.         $connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect';
  118.  
  119.         $this->connection = @$connect_function($dbname, $user, $pw);
  120.         if (!is_resource($this->connection)) {
  121.             return $this->ifxraiseError(DB_ERROR_CONNECT_FAILED);
  122.         }
  123.         return DB_OK;
  124.     }
  125.  
  126.     // }}}
  127.     // {{{ disconnect()
  128.  
  129.     /**
  130.      * Log out and disconnect from the database.
  131.      *
  132.      * @return bool true on success, false if not connected.
  133.      */
  134.     function disconnect()
  135.     {
  136.         $ret = @ifx_close($this->connection);
  137.         $this->connection = null;
  138.         return $ret;
  139.     }
  140.  
  141.     // }}}
  142.     // {{{ simpleQuery()
  143.  
  144.     /**
  145.      * Send a query to Informix and return the results as a
  146.      * Informix resource identifier.
  147.      *
  148.      * @param $query the SQL query
  149.      *
  150.      * @return int returns a valid Informix result for successful SELECT
  151.      * queries, DB_OK for other successful queries.  A DB error code
  152.      * is returned on failure.
  153.      */
  154.     function simpleQuery($query)
  155.     {
  156.         $ismanip = DB::isManip($query);
  157.         $this->last_query = $query;
  158.         $this->affected   = null;
  159.         if (preg_match('/(SELECT)/i', $query)) {    //TESTME: Use !DB::isManip()?
  160.             // the scroll is needed for fetching absolute row numbers
  161.             // in a select query result
  162.             $result = @ifx_query($query, $this->connection, IFX_SCROLL);
  163.         } else {
  164.             if (!$this->autocommit && $ismanip) {
  165.                 if ($this->transaction_opcount == 0) {
  166.                     $result = @ifx_query('BEGIN WORK', $this->connection);
  167.                     if (!$result) {
  168.                         return $this->ifxraiseError();
  169.                     }
  170.                 }
  171.                 $this->transaction_opcount++;
  172.             }
  173.             $result = @ifx_query($query, $this->connection);
  174.         }
  175.         if (!$result) {
  176.             return $this->ifxraiseError();
  177.         }
  178.         $this->affected = @ifx_affected_rows($result);
  179.         // Determine which queries should return data, and which
  180.         // should return an error code only.
  181.         if (preg_match('/(SELECT)/i', $query)) {
  182.             return $result;
  183.         }
  184.         // XXX Testme: free results inside a transaction
  185.         // may cause to stop it and commit the work?
  186.  
  187.         // Result has to be freed even with a insert or update
  188.         @ifx_free_result($result);
  189.  
  190.         return DB_OK;
  191.     }
  192.  
  193.     // }}}
  194.     // {{{ nextResult()
  195.  
  196.     /**
  197.      * Move the internal ifx result pointer to the next available result
  198.      *
  199.      * @param a valid fbsql result resource
  200.      *
  201.      * @access public
  202.      *
  203.      * @return true if a result is available otherwise return false
  204.      */
  205.     function nextResult($result)
  206.     {
  207.         return false;
  208.     }
  209.  
  210.     // }}}
  211.     // {{{ affectedRows()
  212.  
  213.     /**
  214.      * Gets the number of rows affected by the last query.
  215.      * if the last query was a select, returns 0.
  216.      *
  217.      * @return number of rows affected by the last query
  218.      */
  219.     function affectedRows()
  220.     {
  221.         if (DB::isManip($this->last_query)) {
  222.             return $this->affected;
  223.         } else {
  224.             return 0;
  225.         }
  226.         
  227.     }
  228.  
  229.     // }}}
  230.     // {{{ fetchInto()
  231.  
  232.     /**
  233.      * Fetch a row and insert the data into an existing array.
  234.      *
  235.      * Formating of the array and the data therein are configurable.
  236.      * See DB_result::fetchInto() for more information.
  237.      *
  238.      * @param resource $result    query result identifier
  239.      * @param array    $arr       (reference) array where data from the row
  240.      *                            should be placed
  241.      * @param int      $fetchmode how the resulting array should be indexed
  242.      * @param int      $rownum    the row number to fetch
  243.      *
  244.      * @return mixed DB_OK on success, null when end of result set is
  245.      *               reached or on failure
  246.      *
  247.      * @see DB_result::fetchInto()
  248.      * @access private
  249.      */
  250.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  251.     {
  252.         if (($rownum !== null) && ($rownum < 0)) {
  253.             return null;
  254.         }
  255.         if ($rownum === null) {
  256.             /*
  257.              * Even though fetch_row() should return the next row  if
  258.              * $rownum is null, it doesn't in all cases.  Bug 598.
  259.              */
  260.             $rownum = 'NEXT';
  261.         } else {
  262.             // Index starts at row 1, unlike most DBMS's starting at 0.
  263.             $rownum++;
  264.         }
  265.         if (!$arr = @ifx_fetch_row($result, $rownum)) {
  266.             return null;
  267.         }
  268.         if ($fetchmode !== DB_FETCHMODE_ASSOC) {
  269.             $i=0;
  270.             $order = array();
  271.             foreach ($arr as $val) {
  272.                 $order[$i++] = $val;
  273.             }
  274.             $arr = $order;
  275.         } elseif ($fetchmode == DB_FETCHMODE_ASSOC &&
  276.                   $this->options['portability'] & DB_PORTABILITY_LOWERCASE)
  277.         {
  278.             $arr = array_change_key_case($arr, CASE_LOWER);
  279.         }
  280.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  281.             $this->_rtrimArrayValues($arr);
  282.         }
  283.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  284.             $this->_convertNullArrayValuesToEmpty($arr);
  285.         }
  286.         return DB_OK;
  287.     }
  288.  
  289.     // }}}
  290.     // {{{ numRows()
  291.  
  292.     function numRows($result)
  293.     {
  294.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  295.     }
  296.  
  297.     // }}}
  298.     // {{{ numCols()
  299.  
  300.     /**
  301.      * Get the number of columns in a result set.
  302.      *
  303.      * @param $result Informix result identifier
  304.      *
  305.      * @return int the number of columns per row in $result
  306.      */
  307.     function numCols($result)
  308.     {
  309.         if (!$cols = @ifx_num_fields($result)) {
  310.             return $this->ifxraiseError();
  311.         }
  312.         return $cols;
  313.     }
  314.  
  315.     // }}}
  316.     // {{{ freeResult()
  317.  
  318.     /**
  319.      * Free the internal resources associated with $result.
  320.      *
  321.      * @param $result Informix result identifier
  322.      *
  323.      * @return bool true on success, false if $result is invalid
  324.      */
  325.     function freeResult($result)
  326.     {
  327.         return @ifx_free_result($result);
  328.     }
  329.  
  330.     // }}}
  331.     // {{{ autoCommit()
  332.  
  333.     /**
  334.      * Enable/disable automatic commits
  335.      */
  336.     function autoCommit($onoff = true)
  337.     {
  338.         // XXX if $this->transaction_opcount > 0, we should probably
  339.         // issue a warning here.
  340.         $this->autocommit = $onoff ? true : false;
  341.         return DB_OK;
  342.     }
  343.  
  344.     // }}}
  345.     // {{{ commit()
  346.  
  347.     /**
  348.      * Commit the current transaction.
  349.      */
  350.     function commit()
  351.     {
  352.         if ($this->transaction_opcount > 0) {
  353.             $result = @ifx_query('COMMIT WORK', $this->connection);
  354.             $this->transaction_opcount = 0;
  355.             if (!$result) {
  356.                 return $this->ifxRaiseError();
  357.             }
  358.         }
  359.         return DB_OK;
  360.     }
  361.  
  362.     // }}}
  363.     // {{{ rollback()
  364.  
  365.     /**
  366.      * Roll back (undo) the current transaction.
  367.      */
  368.     function rollback()
  369.     {
  370.         if ($this->transaction_opcount > 0) {
  371.             $result = @ifx_query('ROLLBACK WORK', $this->connection);
  372.             $this->transaction_opcount = 0;
  373.             if (!$result) {
  374.                 return $this->ifxRaiseError();
  375.             }
  376.         }
  377.         return DB_OK;
  378.     }
  379.  
  380.     // }}}
  381.     // {{{ ifxraiseError()
  382.  
  383.     /**
  384.      * Gather information about an error, then use that info to create a
  385.      * DB error object and finally return that object.
  386.      *
  387.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  388.      *                          manually raising an error
  389.      * @return object  DB error object
  390.      * @see errorNative()
  391.      * @see errorCode()
  392.      * @see DB_common::raiseError()
  393.      */
  394.     function ifxraiseError($errno = null)
  395.     {
  396.         if ($errno === null) {
  397.             $errno = $this->errorCode(ifx_error());
  398.         }
  399.  
  400.         return $this->raiseError($errno, null, null, null,
  401.                             $this->errorNative());
  402.     }
  403.  
  404.     // }}}
  405.     // {{{ errorCode()
  406.  
  407.     /**
  408.      * Map native error codes to DB's portable ones.
  409.      *
  410.      * Requires that the DB implementation's constructor fills
  411.      * in the <var>$errorcode_map</var> property.
  412.      *
  413.      * @param  string  $nativecode  error code returned by the database
  414.      * @return int a portable DB error code, or DB_ERROR if this DB
  415.      * implementation has no mapping for the given error code.
  416.      */
  417.     function errorCode($nativecode)
  418.     {
  419.         if (ereg('SQLCODE=(.*)]', $nativecode, $match)) {
  420.             $code = $match[1];
  421.             if (isset($this->errorcode_map[$code])) {
  422.                 return $this->errorcode_map[$code];
  423.             }
  424.         }
  425.         return DB_ERROR;
  426.     }
  427.  
  428.     // }}}
  429.     // {{{ errorNative()
  430.  
  431.     /**
  432.      * Get the native error message of the last error (if any) that
  433.      * occured on the current connection.
  434.      *
  435.      * @return int native Informix error code
  436.      */
  437.     function errorNative()
  438.     {
  439.         return @ifx_error() . ' ' . @ifx_errormsg();
  440.     }
  441.  
  442.     // }}}
  443.     // {{{ getSpecialQuery()
  444.  
  445.     /**
  446.      * Returns the query needed to get some backend info
  447.      * @param string $type What kind of info you want to retrieve
  448.      * @return string The SQL query string
  449.      */
  450.     function getSpecialQuery($type)
  451.     {
  452.         switch ($type) {
  453.             case 'tables':
  454.                 return 'select tabname from systables where tabid >= 100';
  455.             default:
  456.                 return null;
  457.         }
  458.     }
  459.  
  460.     // }}}
  461.     // {{{ tableInfo()
  462.  
  463.     /**
  464.      * Returns information about a table or a result set.
  465.      *
  466.      * NOTE: only supports 'table' if <var>$result</var> is a table name.
  467.      *
  468.      * If analyzing a query result and the result has duplicate field names,
  469.      * an error will be raised saying
  470.      * <samp>can't distinguish duplicate field names</samp>.
  471.      *
  472.      * @param object|string  $result  DB_result object from a query or a
  473.      *                                string containing the name of a table
  474.      * @param int            $mode    a valid tableInfo mode
  475.      * @return array  an associative array with the information requested
  476.      *                or an error object if something is wrong
  477.      * @access public
  478.      * @internal
  479.      * @since 1.6.0
  480.      * @see DB_common::tableInfo()
  481.      */
  482.     function tableInfo($result, $mode = null)
  483.     {
  484.         if (isset($result->result)) {
  485.             /*
  486.              * Probably received a result object.
  487.              * Extract the result resource identifier.
  488.              */
  489.             $id = $result->result;
  490.             $got_string = false;
  491.         } elseif (is_string($result)) {
  492.             /*
  493.              * Probably received a table name.
  494.              * Create a result resource identifier.
  495.              */
  496.             $id = @ifx_query("SELECT * FROM $result WHERE 1=0",
  497.                              $this->connection);
  498.             $got_string = true;
  499.         } else {
  500.             /*
  501.              * Probably received a result resource identifier.
  502.              * Copy it.
  503.              */
  504.             $id = $result;
  505.             $got_string = false;
  506.         }
  507.  
  508.         if (!is_resource($id)) {
  509.             return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA);
  510.         }
  511.  
  512.         $flds = @ifx_fieldproperties($id);
  513.         $count = @ifx_num_fields($id);
  514.  
  515.         if (count($flds) != $count) {
  516.             return $this->raiseError("can't distinguish duplicate field names");
  517.         }
  518.  
  519.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  520.             $case_func = 'strtolower';
  521.         } else {
  522.             $case_func = 'strval';
  523.         }
  524.  
  525.         $i = 0;
  526.         // made this IF due to performance (one if is faster than $count if's)
  527.         if (!$mode) {
  528.             foreach ($flds as $key => $value) {
  529.                 $props = explode(';', $value);
  530.  
  531.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  532.                 $res[$i]['name']  = $case_func($key);
  533.                 $res[$i]['type']  = $props[0];
  534.                 $res[$i]['len']   = $props[1];
  535.                 $res[$i]['flags'] = $props[4] == 'N' ? 'not_null' : '';
  536.                 $i++;
  537.             }
  538.  
  539.         } else { // full
  540.             $res['num_fields'] = $count;
  541.  
  542.             foreach ($flds as $key => $value) {
  543.                 $props = explode(';', $value);
  544.  
  545.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  546.                 $res[$i]['name']  = $case_func($key);
  547.                 $res[$i]['type']  = $props[0];
  548.                 $res[$i]['len']   = $props[1];
  549.                 $res[$i]['flags'] = $props[4] == 'N' ? 'not_null' : '';
  550.  
  551.                 if ($mode & DB_TABLEINFO_ORDER) {
  552.                     $res['order'][$res[$i]['name']] = $i;
  553.                 }
  554.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  555.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  556.                 }
  557.                 $i++;
  558.             }
  559.         }
  560.  
  561.         // free the result only if we were called on a table
  562.         if ($got_string) {
  563.             @ifx_free_result($id);
  564.         }
  565.         return $res;
  566.     }
  567.  
  568.     // }}}
  569.  
  570. }
  571.  
  572. /*
  573.  * Local variables:
  574.  * tab-width: 4
  575.  * c-basic-offset: 4
  576.  * End:
  577.  */
  578.  
  579. ?>
  580.